/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package pl.edu.amu.wmi.kino.visualjavafx.visualjavafxgui.editor.visual.widgets;

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import org.netbeans.api.visual.action.ActionFactory;
import org.netbeans.api.visual.action.MoveProvider;
import org.netbeans.api.visual.action.MoveStrategy;
import org.netbeans.api.visual.action.ResizeProvider;
import org.netbeans.api.visual.action.ResizeStrategy;
import org.netbeans.api.visual.action.WidgetAction;
import org.netbeans.api.visual.border.Border;
import org.netbeans.api.visual.border.BorderFactory;
import org.netbeans.api.visual.model.ObjectState;
import org.netbeans.api.visual.widget.Scene;
import org.netbeans.api.visual.widget.Widget;
import org.openide.util.Lookup;
import org.openide.util.lookup.AbstractLookup;
import org.openide.util.lookup.InstanceContent;
import pl.edu.amu.wmi.kino.visualjavafx.model.api.ModelChangeEvent;
import pl.edu.amu.wmi.kino.visualjavafx.model.api.ModelChangeListener;
import pl.edu.amu.wmi.kino.visualjavafx.model.objects.VisualObject;
import pl.edu.amu.wmi.kino.visualjavafx.model.objects.shapes.Elipse;
import pl.edu.amu.wmi.kino.visualjavafx.visualjavafxgui.editor.visual.widgets.VisualObjectWidget.Synchronizer;

/**
 *
 * @author psychollek
 */
public class VisualObjectWidget extends Widget {


        private VisualObject vo;
        protected final InstanceContent ic = new InstanceContent();
        private final Lookup lookup = new AbstractLookup(ic);
        private static final Border RESIZE_BORDER = BorderFactory.createResizeBorder(8,Color.BLACK,true);
        private static final Border DEFAULT_BORDER =BorderFactory.createEmptyBorder(8);

    public VisualObjectWidget(Scene scene, VisualObject vo){
        super(scene);
        this.vo = vo;

        setLocation();
        prepareActions(scene);

        ic.add(vo);
        ic.add(new Synchronizer(this));
    }

    private void prepareActions(Scene scene){
        // guess what ? resize has to be before move ...
        this.getActions().addAction(VOActionFactory.createResizeAction());
        this.getActions().addAction(VOActionFactory.createMoveAction() );        
    }

    private void setLocation(){
            Point p = new Point();
            p.setLocation((vo.getHPos()), (vo.getVPos()));
            this.setPreferredLocation(p);
    }

    @Override
    public Rectangle calculateClientArea(){
        Rectangle r = new Rectangle();
        r.setRect(0,0,vo.getSizeH(),vo.getSizeV());
        return r;
    }

    @Override
    public final Lookup getLookup(){
        return lookup;
    }

    protected void setModelObjectProperties(){
        vo.setHPos(this.getPreferredLocation().getX());
        vo.setVPos(this.getPreferredLocation().getY());
        vo.setSizeV(this.getPreferredBounds().getHeight()-16);
        vo.setSizeH(this.getPreferredBounds().getWidth()-16);
    }

    public void backingModelObjectchanged(){
        this.setLocation();
        this.revalidate();
    }

    public class Synchronizer{

        VisualObjectWidget vow = null;

        Synchronizer(VisualObjectWidget vow){
            this.vow = vow;
        }

        public void modelToWidget(){
            vow.backingModelObjectchanged();
        }

        public void widgetToModel(){
            vow.setModelObjectProperties();
            ModelChangeListener mcl = getScene().getLookup().lookup(ModelChangeListener.class);
            if (mcl != null){
                mcl.notifyModelChange(ModelChangeEvent.propertyChanged(vow, vo, "transformable"));
            }
        }
    }

    @Override
    public void notifyStateChanged(ObjectState previousState, ObjectState newState) {
        super.notifyStateChanged(previousState, newState);
        setBorder(newState.isSelected() ? RESIZE_BORDER : DEFAULT_BORDER);
     }

}

class VOActionFactory{

    private static final MoveStrategy MOVE_STRATEGY = new MoveStrategy () {
        @Override
        public Point locationSuggested (Widget widget, Point originalLocation, Point suggestedLocation) {
            return suggestedLocation;
        }
    };

    private static final MoveProvider MOVE_PROVIDER = new MoveProvider () {
        @Override
        public void movementStarted (Widget widget) {

        }
        @Override
        public void movementFinished (Widget widget) {
            Synchronizer sync = widget.getLookup().lookup(Synchronizer.class);
            if (sync != null){
                sync.widgetToModel();
            }
        }
        @Override
        public Point getOriginalLocation (Widget widget) {
            return widget.getPreferredLocation ();
        }
        @Override
        public void setNewLocation (Widget widget, Point location) {
            widget.setPreferredLocation (location);
        }
    };

    public static WidgetAction createMoveAction(){
        return ActionFactory.createMoveAction(MOVE_STRATEGY, MOVE_PROVIDER);    
    }

    public static WidgetAction createResizeAction(){

        final class Data{
            Rectangle org = new Rectangle();
            Rectangle chd = new Rectangle();
            Point orgloc = new Point();
        }

        final Data d = new Data();

        ResizeProvider RESIZE_PROVIDER = new ResizeProvider () {

            @Override
            public void resizingStarted(Widget widget) {
                d.orgloc = widget.getPreferredLocation();
            }

            @Override
            public void resizingFinished(Widget widget) {

                Point p = new Point(0,0);

                if (widget.getLookup().lookup(Elipse.class) != null){
                    p = d.orgloc;

                    int dx = (d.chd.width - d.org.width)/2;
                    if((d.chd.x - d.org.x) != 0) dx = -dx;
                    p.x = p.x + dx;

                    int dy = (d.chd.height - d.org.height)/2;
                    if((d.chd.y - d.org.y) != 0) dy = -dy;
                    p.y = p.y + dy;

                    d.chd.x = -(d.chd.width / 2);
                    d.chd.y = -(d.chd.height / 2);

                }else{

                    int dx = d.chd.x - d.org.x;
                    int dy = d.chd.y - d.org.y;

                    int newx = d.orgloc.x + dx;
                    int newy = d.orgloc.y + dy;

                    p = new Point(newx,newy);

                    //the borders !
                    d.chd.x = -8;
                    d.chd.y = -8;

                }
                
                widget.setPreferredLocation(p);
                widget.setPreferredBounds(d.chd);

                Synchronizer sync = widget.getLookup().lookup(Synchronizer.class);
                if (sync != null){
                    sync.widgetToModel();
                }
            }

        };

        ResizeStrategy RESIZE_STRATEGY= new ResizeStrategy () {
            @Override
            public Rectangle boundsSuggested (Widget widget, Rectangle originalBounds, Rectangle suggestedBounds, ResizeProvider.ControlPoint controlPoint) {
                d.org = originalBounds;
                d.chd = suggestedBounds;
                return suggestedBounds;
            }
        };

        return ActionFactory.createResizeAction(RESIZE_STRATEGY, null, RESIZE_PROVIDER);
    }

}